using UnityEngine;
using System;
using System.Collections.Generic;
using System.Collections;
// Refactoring from flash project

public class Gesture
{
	public String name;
	public String moves;
	public Gesture(String name,String moves)
	{
		this.name = name;
		this.moves = moves;
	}
}

public class Levenshetin
{
	public static uint defaultSectors = 8;			// Number of sectors
	public static uint distForDirCalcuation = 5;	// calculate a direction defined by two points only when they are far away (say 5px).
	public static uint fiability = 5;			// Default fiability level
	public static uint sector_angle = 360 / defaultSectors;// 45
	
	private Vector2 lastPoint;
	
	private String lastGest = null;
	private String currentGest = null;// current gesture
	private List<Gesture> gestures;	// predefined gestures
	
	private Gesture bestGesture;
	
	public Levenshetin ()
	{
		lastPoint = new Vector2();
		currentGest = null;
		bestGesture = null;
		gestures = new List<Gesture>();
		
		
		
		
	}
	public String lastGesture
	{
		get{return lastGest;}
	}
	public void addGesture(String name,String gesture) // explicitly untyped variable 
	{
		gestures.Add(new Gesture(name,gesture));
	}
	
	public void onCatureStart(Touch e)
	{
		currentGest = "";
		lastPoint = e.position;
	}
	public void onGestureCapturing(Touch e)
	{
				
		// calculating moving direction if the distance between
		// the current point and the last point is large enough (say 8 px);
		// otherwise direction calculation is not very reliable
		
		Vector2 current = e.position;
		Vector2 offset = current - lastPoint;
		
		if (offset.x*offset.x + offset.y*offset.y > 
		distForDirCalcuation * distForDirCalcuation)
		{
			int angle = (int)(Mathf.Atan2(offset.y,offset.x) * 180 / Mathf.PI);
			if (angle < 0)	angle = angle + 360;
					
		
			// update the positin of last point 
			lastPoint = current;

			// assign numbers between 0 and 7 as directions	 
			int sector =(int)( (angle + sector_angle/2) % 360 / sector_angle);
					
			currentGest += sector.ToString();
		}
			
	}
	public void onCatpureEnd(Touch e)
	{
			

			// check if the current mouse gesture is similar to any predefined gesture 
			// and if any choose the most similar one
			uint bestCost = 10000000;
			

			for (int i = 0; i < gestures.Count; i++)
			{
				Gesture gest = gestures[i];
				uint cost = Compute(gest.moves,currentGest);
				if (cost < bestCost)
				{
					bestCost = cost;
					bestGesture = gestures[i];
				}
			}

			
			if (bestCost < fiability)
			{	
				// gesture reconized 
				//	print( bestGesture.datas + "; Cost: " + bestCost);
			}
			else
			{
				//print( "no recognized gesture." + " Cost: " + bestCost);
				bestGesture = null;
			}
			lastGest = currentGest;
			currentGest = null;// reset
		}
	// compute Levenshtein distance between two strings (a & b)
	// http://en.wikipedia.org/wiki/Levenshtein_distance
	public static UInt32 Compute(String a,String b)
	{
		
			int x = 0,y = 0;
			// point
			if (a.Length == 0)
			{
				return (UInt32)(b.Length==0 ? 0 : 100000);
			}
		
			
			// precalc difangles
			ArrayList d = new ArrayList(a.Length + 1);
			for ( x=0; x<a.Length+1; x++)
			{
				ArrayList temp = new ArrayList(b.Length + 1);
				
				for ( y=0; y<b.Length+1; y++)
				{
					temp.Add((UInt32)0);
				}
				d.Add(temp);
			}

			ArrayList w = (ArrayList)d.Clone();

			for ( x=1; x<=a.Length; x++)
			{
				ArrayList tempX = (ArrayList)w[x];
				for ( y=1; y<b.Length; y++)
				{
					
					UInt32 dif = (UInt32) Math.Abs(a[x - 1] - b[y - 1]);
					if (dif > defaultSectors / 2)
					{
						dif = defaultSectors - dif;
					}
					tempX[y] = (UInt32)dif;
				}
			}
		
		
			// max cost
			for ( y=1; y<=b.Length; y++)
			{
				((ArrayList)w[0])[y] = (UInt32)100000;
			}
			for ( x=1; x<=a.Length; x++)
			{
				((ArrayList)w[x])[0] = (UInt32)100000;
			}
			((ArrayList)w[0])[0] = (UInt32)0;

			// levensthein application
			UInt32 cost = (UInt32)0;
			UInt32 pa;
			UInt32 pb;
			UInt32 pc;

			for ( x=1; x<=a.Length; x++)
			{
				for ( y=1; y<b.Length; y++)
				{
					cost = (UInt32)(((ArrayList)d[x])[y]);
					pa = (UInt32)(((ArrayList)w[x - 1])[y	 ]) + cost;
					pb = (UInt32)(((ArrayList)w[x	 ])[y - 1]) + cost;
					pc = (UInt32)(((ArrayList)w[x - 1])[y - 1])  + cost;
					((ArrayList)w[x])[y] = (UInt32)Mathf.Min(Mathf.Min(pa,pb),pc);
				}
			}

			return	(UInt32)((ArrayList)w[x-1])[y-1];
		}

	
}


